#include "hash_map.h"

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void map_init(hash_map* m, hash_Fn hash_fn, equal_Fn equal_fn, unsigned int bucket_size)
{
    memset(m, 0, sizeof(hash_map));
    m->bucket = (map_entry**)malloc(bucket_size * sizeof(map_entry*));
    memset(m->bucket, 0, bucket_size * sizeof(map_entry*));
    m->equalf = equal_fn; // 初始化时自定义 equql和hash函数
    m->hashf = hash_fn;
    m->mask = 0xffff;
    m->cur = -1;
    m->size = bucket_size;
}

int map_put(hash_map* m, map_entry* entry)
{
    unsigned int hash = m->hashf(entry->key);
    uint32_t pos = hash & m->mask;
    map_entry* en = (map_entry*)malloc(sizeof(map_entry));
    memset(en, 0, sizeof(map_entry));
    en->key = entry->key;
    en->val = entry->val;

    map_entry* e = m->bucket[pos];
    while (e) {
        if (m->equalf(e->key, entry->key)) {
            e->val = en->val;
            return 1; // exist
        }
        e = e->next;
    }
    en->next = m->bucket[pos];
    m->bucket[pos] = en;
    m->used += 1;
    return 0;
}

map_entry* map_get(hash_map* m, void* key)
{
    unsigned int hash = m->hashf(key);
    uint32_t pos = hash & m->mask;
    // printf("map_get: key=%s pos=%d\n", (char*)key, pos);
    map_entry* e = m->bucket[pos];
    while (e) {
        if (m->equalf(e->key, key)) {
            return e;
        }
        e = e->next;
    }
    return NULL;
}

map_entry* map_del(hash_map* m, void* key)
{
    unsigned int hash = m->hashf(key);
    uint32_t pos = hash & m->mask;
    map_entry* e = m->bucket[pos];
    map_entry** prev = &m->bucket[pos];
    while (e) {
        if (m->equalf(e->key, key)) {
            *prev = e->next;
            m->used -= 1;
            return e;
        }
        *prev = e;
        e = e->next;
    }
    return NULL;
}

unsigned int time33(char* str)
{
    unsigned int hash = 5381;
    while (*str) {
        hash += (hash << 5) + (*str++);
    }
    return (hash & 0x7FFFFFFF);
}

/* MurmurHash2, by Austin Appleby
 * Note - This code makes a few assumptions about how your machine behaves -
 * 1. We can read a 4-byte value from any address without crashing
 * 2. sizeof(int) == 4
 *
 * And it has a few limitations -
 *
 * 1. It will not work incrementally.
 * 2. It will not produce the same results on little-endian and big-endian
 *    machines.
 */
unsigned int murmur_hash(const void* key, int len)
{
    /* 'm' and 'r' are mixing constants generated offline.
     They're not really 'magic', they just happen to work well.  */
    uint32_t seed = 5381;
    const uint32_t m = 0x5bd1e995;
    const int r = 24;

    /* Initialize the hash to a 'random' value */
    uint32_t h = seed ^ len;

    /* Mix 4 bytes at a time into the hash */
    const unsigned char* data = (const unsigned char*)key;

    while (len >= 4) {
        uint32_t k = *(uint32_t*)data;

        k *= m;
        k ^= k >> r;
        k *= m;

        h *= m;
        h ^= k;

        data += 4;
        len -= 4;
    }

    /* Handle the last few bytes of the input array  */
    switch (len) {
        case 3:
            h ^= data[2] << 16;
        case 2:
            h ^= data[1] << 8;
        case 1:
            h ^= data[0];
            h *= m;
    };

    /* Do a few final mixes of the hash to ensure the last few
     * bytes are well-incorporated. */
    h ^= h >> 13;
    h *= m;
    h ^= h >> 15;

    return (unsigned int)h;
}

/* Thomas Wang's 32 bit Mix Function */
unsigned int dict_int_hash(unsigned int key)
{
    key += ~(key << 15);
    key ^= (key >> 10);
    key += (key << 3);
    key ^= (key >> 6);
    key += ~(key << 11);
    key ^= (key >> 16);
    return key;
}